package rollercoaster.railway;

import java.util.ArrayList;
import java.util.List;

import rollercoaster.commons.Vertex3D;
import rollercoaster.commons.interfaces.ICurve3D;
import rollercoaster.railway.utils.VertexUtils;

public class UniformSecondOrderClosedBSpline implements ICurve3D{

	List<Vertex3D> controlPoints=new ArrayList<Vertex3D>();
	private float newt;
	private Vertex3D start;
	private Vertex3D mid;
	private Vertex3D end;
	
	public UniformSecondOrderClosedBSpline(List<Vertex3D> controlPoints) {
		super();
		this.controlPoints = controlPoints;
	}
	
	public List<Vertex3D> getControlPoints() {
		return controlPoints;
	}




	public void setControlPoints(List<Vertex3D> controlPoints) {
		this.controlPoints = controlPoints;
	}
	


	
	public Vertex3D gamma(float t) {
		focusOnInterval(t);
		
		float valuex=(1-newt)*(1-newt)*start.getX()+2*newt*(1-newt)*mid.getX()+newt*newt*end.getX();
		float valuey=(1-newt)*(1-newt)*start.getY()+2*newt*(1-newt)*mid.getY()+newt*newt*end.getY();
		float valuez=(1-newt)*(1-newt)*start.getZ()+2*newt*(1-newt)*mid.getZ()+newt*newt*end.getZ();
		
		return new Vertex3D(valuex, valuey, valuez);
	}

	public Vertex3D dGammadt(float t) {
		focusOnInterval(t);
		
		float valuex=2*(1-newt)*(mid.getX()-start.getX())+2*newt*(end.getX()-mid.getX());
		float valuey=2*(1-newt)*(mid.getY()-start.getY())+2*newt*(end.getY()-mid.getY());
		float valuez=2*(1-newt)*(mid.getZ()-start.getZ())+2*newt*(end.getZ()-mid.getZ());
		
		return new Vertex3D(valuex, valuey, valuez);
	}
	


	private float normalize(float t) {

		while(t<0){
			t+=controlPoints.size();
		}
		while(t>=controlPoints.size()){
			t-=controlPoints.size();
		}
		return t;
	}
	
	private void focusOnInterval(float t) {
		t=normalize(t);
		int interval=(int)(t);
		
		newt=t-interval;
		
		int max=controlPoints.size();
		Vertex3D P1=controlPoints.get(interval%max);
		mid=controlPoints.get((interval+1)%max);
		Vertex3D P3=controlPoints.get((interval+2)%max);
		
		start=VertexUtils.meanPoint(P1, mid);
		end=VertexUtils.meanPoint(P3, mid);
	}

	public float getStartPoint() {
		return 0;
	}

	public float getEndPoint() {
		return controlPoints.size();
	}
}
